﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using MySql.Simple.Mapper.Linq.ExpressionVisitors;

namespace MySql.Simple.Mapper.Linq
{
    /// <summary>
    /// Generates a MySQL SQL WHERE clause fragment based a LINQ <see cref="Expression"/>.
    /// </summary>
    public class SqlGenerator
    {
        // Private fields
        private readonly IList<IExpressionVisitor> expressionVisitors;

        /// <summary>
        /// Initializes a new instance of the <see cref="SqlGenerator"/> class.
        /// </summary>
        public SqlGenerator()
        {
            expressionVisitors = new List<IExpressionVisitor>
                                     {
                                         new NewExpressionVisitor(),
                                         new ConstantExpressionVisitor(),
                                         new MemberExpressionVisitor(),
                                         new LambdaExpressionVisitor(),
                                         new BinaryExpressionVisitor(),
                                         new MethodCallExpressionVisitor(),
                                         new UnaryExpressionVisitor()
                                     };
        }

        public string Generate(IQueryable queryable)
        {
            return Generate(queryable.Expression);
        }

        public string Generate(Expression expression)
        {
            return Generate(expression, new SqlQuery()).ToString();
        }

        public SqlQuery Generate(Expression expression, SqlQuery query)
        {
            foreach (var expressionVisitor in expressionVisitors)
            {
                if (expressionVisitor.CanVisit(expression))
                {
                    query = expressionVisitor.Visit(expression, query);
                }
            }

            return query;
        }

        public string Where<T>(Expression<Func<T, object>> expression)
        {
            return Generate(expression);
        }              
    }
}